package com.google.code.jnextbigsound;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.io.IOException;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * This class provides access to the spotify metadata API
 */
public class NextBigSound {

	private Commander commander;
	
	private static Logger logger = Logger.getLogger(NextBigSound.class);

	public NextBigSound() throws IOException {
		commander = new Commander("nextbigsound",
				"http://key.api3.nextbigsound.com", "");
		commander.setRetries(1);
		commander.setTimeout(10000);
		commander.setTraceSends(false);
	}

	/**
	 * Search for an artist by name
	 * 
	 * @param query
	 *            the name of the artist
	 * @param page
	 *            the page number
	 * @return a list of artists
	 * @throws IOException
	 */
	public NextBigSoundResponse searchArtist(String query) throws IOException {
		String encodedArtist = URLEncoder.encode(query, "UTF-8");
		Document doc = commander.sendCommand("/artists/search.xml?q="
				+ encodedArtist);
		Element docElement = doc.getDocumentElement();
		String status = XmlUtil.getDescendentText(docElement, "status");
		String message = XmlUtil.getDescendentText(docElement, "message");

		NextBigSoundResponse response = new NextBigSoundResponse();
		response.setStatus(status);
		response.setMessage(message);

		if (NextBigSoundResponse.ERROR.equalsIgnoreCase(status)) {
			return response;
		} else {
			NodeList artists = docElement.getElementsByTagName("artist");
			ArtistSearchResponseData responseData = new ArtistSearchResponseData();
			List<Artist> artistList = new ArrayList<Artist>();
			for (int i = 0; i < artists.getLength(); i++) {
				Element artistNode = (Element) artists.item(i);
				String id = artistNode.getAttribute("id");
				String name = XmlUtil.getDescendentText(artistNode, "name");
				String mid = XmlUtil.getDescendentText(artistNode,
						"music_brainz_id");
				Artist artist = new Artist(id, name, mid);
				artistList.add(artist);
			}
			responseData.setArtists(artistList);
			response.setData(responseData);
			return response;
		}
	}

	/**
	 * Search for an artist by name
	 * 
	 * @param query
	 *            the name of the artist
	 * @param page
	 *            the page number
	 * @return a list of artists
	 * @throws IOException
	 */
	public NextBigSoundResponse searchArtistProfiles(String artistId)
			throws Exception {
		NextBigSoundResponse response = new NextBigSoundResponse();
		try {
			String encodedArtistId = URLEncoder
					.encode(artistId.trim(), "UTF-8");
			Document doc = commander.sendCommand("/profiles/artist/"
					+ encodedArtistId + ".xml");
			// printXmlString(doc);
			Element docElement = doc.getDocumentElement();
			String status = XmlUtil.getDescendentText(docElement, "status");
			String message = XmlUtil.getDescendentText(docElement, "message");

			response.setStatus(status);
			response.setMessage(message);

			if (NextBigSoundResponse.ERROR.equalsIgnoreCase(status)) {
				return response;
				// log somthing there
			} else {
				ArtistProfileResponseData responseData = new ArtistProfileResponseData();
				// get only one artist info
				NodeList artists = docElement.getElementsByTagName("artist");
				if (artists != null && artists.getLength() > 0) {
					Element artistNode = (Element) artists.item(0);
					String id = artistNode.getAttribute("id");
					String name = XmlUtil.getDescendentText(artistNode, "name");
					Artist artist = new Artist(id, name, null);
					responseData.setArtist(artist);
				}
				// get list of artist profiles
				NodeList profiles = docElement.getElementsByTagName("profile");
				List<Profile> profileList = new ArrayList<Profile>();
				for (int i = 0; i < profiles.getLength(); i++) {
					Element profileNode = (Element) profiles.item(i);
					String id = profileNode.getAttribute("id");
					String url = XmlUtil.getDescendentText(profileNode, "url");
					String serviceName = XmlUtil.getDescendentText(profileNode,
							"service");
					Service service = getArtistProfileService(serviceName);
					boolean locked = XmlUtil.getDescendentTextAsBoolean(
							profileNode, "locked", false);
					Profile profile = new Profile(id, url, service, locked);
					profileList.add(profile);
				}
				responseData.setProfiles(profileList);
				response.setData(responseData);
			}
		} catch (IOException ex) {
			throw ex;
		}
		return response;
	}

	private Service getArtistProfileService(String serviceName) {
		for (Service service : Service.values()) {
			if (service.getHuman().equals(serviceName)) {
				return service;
			}
		}
		return Service.NO_SERVICE;
	}

	public void printXmlString(Document document) {
		TransformerFactory transfac = TransformerFactory.newInstance();
		try {
			Transformer trans = transfac.newTransformer();
			trans.setOutputProperty(OutputKeys.METHOD, "xml");
			trans.setOutputProperty(OutputKeys.INDENT, "yes");
			trans.setOutputProperty(
					"{http://xml.apache.org/xslt}indent-amount",
					Integer.toString(2));

			StringWriter sw = new StringWriter();
			StreamResult result = new StreamResult(sw);
			DOMSource source = new DOMSource(document.getDocumentElement());

			trans.transform(source, result);
			String xmlString = sw.toString();
			logger.info(xmlString);
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		NextBigSound nbs = new NextBigSound();
		NextBigSoundResponse response = nbs.searchArtist("beyonce");
		ArtistSearchResponseData responseData = (ArtistSearchResponseData) response.getData();
		List<Artist> artists = responseData.getArtists();
		if (!artists.isEmpty()) {
			logger.info("Count " + artists.size());
			for (int i = 0 ; i < 1; i ++) {
				Artist artist = artists.get(i);
				logger.info(artist.getId());
				logger.info(artist.getName());
				NextBigSoundResponse profilerResponse = nbs
						.searchArtistProfiles(artist.getId());
				ArtistProfileResponseData profilerResponseData = (ArtistProfileResponseData) profilerResponse.getData();
				for (Profile profile : profilerResponseData.getProfiles()) {
					logger.info(profile.getService().getHuman() + " : "
							+ profile.getUrl());
				}
			}
		} else {
			logger.info("Error");
		}
	}
}
